package com.innovation.ic.im.end.web.endpoint;

import com.google.common.base.Strings;
import com.innovation.ic.b1b.framework.util.StringUtils;
import com.innovation.ic.im.end.base.model.im_erp9.Account;
import com.innovation.ic.im.end.base.model.im_erp9.GroupMessage;
import com.innovation.ic.im.end.base.pojo.ServiceResult;
import com.innovation.ic.im.end.base.pojo.constant.MessageType;
import com.innovation.ic.im.end.base.pojo.constant.RabbitMqExchangeMap;
import com.innovation.ic.im.end.base.service.helper.ServiceImplHelper;
import com.innovation.ic.im.end.base.vo.im_erp9.GroupMessageVo;
import com.innovation.ic.im.end.web.config.GetHttpSessionConfigurator;
import com.innovation.ic.im.end.web.thread.SaveGroupMessageThread;
import com.jcraft.jsch.ChannelSftp;
import lombok.Data;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Data
@Component
@ServerEndpoint(value = "/ws/v1/group/upload/{groupId}/{username}/{filename}/{type}", configurator = GetHttpSessionConfigurator.class)
public class GroupUploadEndpoint extends AbstractEndpoint {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 建立连接
     *
     * @param groupId
     * @param username
     * @param filename
     * @param session
     * @param config
     */
    @OnOpen
    public void onOpen(@PathParam("groupId") String groupId,
                       @PathParam("username") String username,
                       @PathParam("filename") String filename,
                       @PathParam("type") Integer type,
                       Session session, EndpointConfig config) {
        // 验证参数
        if (null == groupId || !StringUtils.validateParameter(username)
                || !StringUtils.validateParameter(filename) || null == type) {
            logger.warn("参数groupId、username、filename、type不能为空");
            return;
        } else {
            logger.info("session的id为【" + session.getId() + "】，默认群组id【" + groupId + "】" +
                    "用户【" + username + "】文件【" + filename + "】，当前在线人数【" + onlineGroupMap.size() + "】");
        }

        Integer type_ = null;
        if (MessageType.FILE.equals(type)) {
            type_ = MessageType.FILE;
        } else if (MessageType.PICTURE.equals(type)) {
            type_ = MessageType.PICTURE;
        } else {
            logger.warn("session的id为【" + session.getId() + "】，默认群组id【" + groupId + "】" +
                    "用户【" + username + "】文件【" + filename + "】，当前在线人数【" + onlineGroupMap.size() + "】，" +
                    "type参数错误【" + type_ + "】");
        }
        GroupMessageVo groupMessageVo = new GroupMessageVo(groupId, username, null, type_, filename);
        onlineGroupUploadMap.put(session.getId(), groupMessageVo);

        // 注意，此处不用处理未读消息，未读消息在GroupEndpoint类中处理
    }

    /**
     * 报错
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        onlineGroupUploadMap.remove(session.getId());
        logger.info("session id为【" + session.getId() + "】的连接关闭了，关闭原因【" + closeReason.toString() + "】，当前在线人数" + onlineMap.size());
    }

    private static byte[] combineArrays(byte[]... a) {
        int massLength = 0;
        for (byte[] b : a) {
            massLength += b.length;
        }
        byte[] c = new byte[massLength];
        byte[] d;
        int index = 0;
        for (byte[] anA : a) {
            d = anA;
            System.arraycopy(d, 0, c, 0 + index, d.length);
            index += d.length;
        }
        return c;
    }

    @OnMessage
    public void processUpload(ByteBuffer byteBuffer, boolean last, Session session) throws Exception {
        // 验证参数
        if (null == byteBuffer) {
            logger.warn("上传的内容不能为空");
            return;
        }

        try {
            GroupMessageVo groupMessageVo = onlineGroupUploadMap.get(session.getId());

            if (!last) {
                ByteBuffer lsByteBuffer = groupMessageVo.getByteBuffer();
                if (lsByteBuffer == null) {
                    groupMessageVo.setByteBuffer(byteBuffer);
                } else {
                    ByteBuffer newByteBuffer = ByteBuffer.allocate(lsByteBuffer.limit() + byteBuffer.limit());
                    newByteBuffer.put(lsByteBuffer);
                    newByteBuffer.put(byteBuffer);
                    newByteBuffer.flip();
                    groupMessageVo.setByteBuffer(newByteBuffer);
                }
                logger.info("last不为true,文件传递不完整,待后续操作");
                return;
            } else {
                if (groupMessageVo.getByteBuffer() != null) {
                    logger.info("在onlineGroupUploadMap中存有其它分片的文件数据,需要拼合为完整文件内容");
                    ByteBuffer newByteBuffer = ByteBuffer.allocate(groupMessageVo.getByteBuffer().limit() + byteBuffer.limit());
                    newByteBuffer.put(groupMessageVo.getByteBuffer());
                    newByteBuffer.put(byteBuffer);
                    newByteBuffer.flip();
                    byteBuffer = newByteBuffer;
                    logger.info("文件byteBuffer拼接完成");
                } else {
                    logger.info("在onlineGroupUploadMap中不存在其它分片的文件数据,byteBuffer为完整内容");
                }
            }

            String filename = groupMessageVo.getFilePath();
            if (!Strings.isNullOrEmpty(filename)) {
                logger.info("-------------接收图片或文件:[{}]---------------", filename);
            }
            Integer type = groupMessageVo.getType();
            if (type.intValue() == MessageType.FILE.intValue()) {
                InputStream inputStream = new ByteArrayInputStream(byteBuffer.array());
                MultipartFile file = new MockMultipartFile(filename, filename, ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
                List<String> upload = ServiceImplHelper.getMinioManager().upload(minioConfig.getBucketName(), new MultipartFile[]{file});
                if (!groupMessageVo.getFilePath().contains(bucketName + File.separator)) {
                    groupMessageVo.setFilePath(bucketName + File.separator + upload.get(0));
                }
                inputStream.close();
            }

            if (type.intValue() == MessageType.PICTURE.intValue()) {
                //获取byteBuffer中有效大小
                int len = byteBuffer.limit() - byteBuffer.position();
                byte[] bytes = new byte[len];
                for (int i = 0; i < bytes.length; i++) {
                    bytes[i] = byteBuffer.get();
                }

                // 获取ChannelSftp连接
                InterProcessMutex lock = new InterProcessMutex(curatorFramework, zookeeperPathWebParamConfig.getGroupEndPointUpload());
                if (lock.acquire(zookeeperParamConfig.getWaitingLockTime(), TimeUnit.SECONDS)) {
                    // 上传文件
                    sftpChannelManager.upload(fileParamConfig.getFileUrl(), bytes, filename);
                    groupMessageVo.setByteBuffer(null);
                    lock.release();
                } else {
                    lock.release();
                }
            }

            if (groupMessageVo != null && Strings.isNullOrEmpty(groupMessageVo.getFromUserRealName())) {
                // 根据用户名获取真实姓名
                ServiceResult<Account> result = accountService.findByAccount(groupMessageVo.getFromUserAccount());
                groupMessageVo.setFromUserRealName(result.getResult().getRealName());
            }

            // 将消息发送给群组中每一个在线的用户，除了自己
            Set<GroupEndpoint> groupEndpointSet = onlineGroupMap.get(groupMessageVo.getGroupId().toString());
            Iterator<GroupEndpoint> groupEndpointIterator = groupEndpointSet.iterator();
            List<String> onlineAccountList = new ArrayList<String>();
            if (groupEndpointIterator != null) {
                while (groupEndpointIterator.hasNext()) {
                    GroupEndpoint groupEndpoint = groupEndpointIterator.next();
                    onlineAccountList.add(groupEndpoint.getAccount());
                }
            }

            // 保存群组消息
            Long waitingLockTime = zookeeperParamConfig.getWaitingLockTime();
            GroupMessage groupMessage = modelHandler.toGroupMessage(groupMessageVo);

            SaveGroupMessageThread saveGroupMessageThread = new SaveGroupMessageThread(groupMessage, curatorFramework, waitingLockTime, onlineAccountList,
                    rabbitMqParamConfig.getExchange().get(RabbitMqExchangeMap.CURRENT_EXCHANGE), groupMessageVo, onlineGroupMap, pictureParamConfig.getUrlprefix(), threadPoolManager);
            threadPoolManager.execute(saveGroupMessageThread);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}